from models.base import Base
import sys
import zipfile
import os.path
import os
import requests
import subprocess


class Game(Base):
    localTable = "games"

    def __init__(self):
        self.localVersion = 0

    @classmethod
    def createFromRow(self, data):
        game = Game()
        game.setId(data[0])
        game.setTitle(data[1])
        game.setDescription(data[2])
        game.setAuthor(data[3])
        game.setLocalVersion(data[4])
        game.setRemoteVersion(data[5])
        return game

    @classmethod
    def createFromJson(self, json):
        game = Game()
        game.setId(json['id'])
        game.setTitle(json['title'])
        game.setDescription(json['description'])
        game.setAuthor(json['author'])
        game.setRemoteVersion(json['remoteVersion'])
        return game

    # Returns the global remote path ("index")
    @classmethod
    def getIndexPath(self):
        return "%s/games" % self.remoteBase

    # Returns the remote path for a single game ("show")
    @classmethod
    def getShowPath(self, game):
        return "%s/games/%d" % (self.remoteBase, game.getId())

    @classmethod
    def save(self, game):
        # if not game.getId():
            # return
        self.connectToDatabase()

        c = self.conn.cursor()
        if game.getId() is None:
            c.execute("""INSERT INTO games (title, description, author,
                      localVersion, remoteVersion) VALUES
                      (?, ?, ?, ?, ?)""",
                      (game.getTitle(), game.getDescription(), game.getAuthor(),
                       0, game.getRemoteVersion(),))
        else:
            c.execute("""UPDATE games SET title = ?, description = ?, author = ?,
                      localVersion = ?, remoteVersion = ?
                      WHERE id = ?""",
                      (game.getTitle(), game.getDescription(), game.getAuthor(),
                       game.getLocalVersion(), game.getRemoteVersion(), game.getId(),))
        self.conn.commit()

    # Setters and getters
    def setId(self, idn):
        self.idn = idn
        return self

    def getId(self):
        return self.idn

    def setTitle(self, title):
        self.title = title
        return self

    def getTitle(self):
        return self.title

    def setAuthor(self, author):
        self.author = author
        return self

    def getAuthor(self):
        return self.author

    def setDescription(self, description):
        self.description = description
        return self

    def getDescription(self):
        return self.description

    def setLocation(self, location):
        self.location = location
        return self

    def getLocation(self):
        return self.location

    def setLocalVersion(self, localVersion):
        self.localVersion = localVersion
        return self

    def getLocalVersion(self):
        return self.localVersion

    def setRemoteVersion(self, remoteVersion):
        self.remoteVersion = remoteVersion
        return self

    def getRemoteVersion(self):
        return self.remoteVersion

    # Returns "ready" (to play), (needs) "update" or (needs) "install"
    def getStatus(self):
        if self.localVersion >= self.remoteVersion:
            return "ready"
        elif self.localVersion == 0:
            return "install"
        elif self.remoteVersion > self.localVersion:
            return "update"

    def install(self):
        directory = "games/%d" % self.getId()
        if not os.path.exists(directory):
            os.makedirs(directory)
        filename = "%s/game.zip" % directory
        r = requests.get("%s/static/%d/game.zip" %
                         (Game.remoteBase, self.getId()),
                         stream=True)
        with open(filename, 'wb') as f:
            for chunk in r.iter_content(chunk_size=1024):
                if chunk:  # Filter out keep-alive new chunks
                    f.write(chunk)
                    f.flush()
        zfile = zipfile.ZipFile(filename)
        for name in zfile.namelist():
            (dirname, filename) = os.path.split(name)
            zfile.extract(name, directory)
        self.setLocalVersion(self.getRemoteVersion())
        Game.save(self)
        return filename

    def launch(self):
        status = self.getStatus()
        print(status)
        if status == "ready":
            # TODO: if Windows, call launch.bat instead
            if sys.platform == 'win32':
                gameDir = os.path.join('', "games\\%d\\launch.bat" % self.getId())
            else:
                gameDir = os.path.join('', "games/%d/launch.sh" % self.getId())
                os.chmod(gameDir, 755)
            print(gameDir)
            subprocess.Popen(gameDir)
        elif status == "install" or status == "update":
            self.install()
            self.launch()

    # Compound accessors
    def getTitleLine(self):
        return "%s by %s" % (self.getTitle(), self.getAuthor())

    # Used for brief attributes in GET /games
    def getAttributes(self):
        return {
            "id": self.getId(),
            "title": self.getTitle(),
            "author": self.getAuthor(),
            "description": self.getDescription(),
            "remoteVersion": self.getRemoteVersion()
        }

    # Used for all attributes in GET /games/:game_id:
    def getAllAttributes(self):
        return self.getAttributes()

    # Used for testing
    @classmethod
    def getMocks(self):
        minecraft = Game()
        minecraft.setId(1)
        minecraft.setTitle("MineCraft")
        minecraft.setDescription("Minecraft is a game about breaking and placing "
                                 "blocks. At first, people built structures to "
                                 "protect against nocturnal monsters, but as the "
                                 "game grew players worked together to create wonderful, "
                                 "imaginative things.")
        minecraft.setAuthor("Mojang, Inc.")
        minecraft.setLocalVersion(1)
        minecraft.setRemoteVersion(1)

        dreadnought = Game()
        dreadnought.setId(2)
        dreadnought.setTitle("Dreadnought")
        dreadnought.setDescription("Dreadnought is a third person tactical space combat "
                                   "simulator. Players will be a part of a team of five "
                                   "capital class space ships trying to eliminate the "
                                   "opposing team. Get ready to crush your foes with "
                                   "missiles, lasers, and more!"
                                   "Dreadnought is not currently available commercially.")

        dreadnought.setAuthor("Greybox LLC")
        dreadnought.setLocalVersion(1)
        dreadnought.setRemoteVersion(1)

        return [minecraft, dreadnought]
